package com.core.cloudcommon.trace;

import com.core.cloudcommon.context.RequestContext;
import com.core.cloudcommon.security.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author =====Lqj=====
 * @className TraceInterceptor
 * @description 链路追踪拦截器
 * @create 2024/12/17 10:30
 **/
@Slf4j
@Component
public class TraceInterceptor implements HandlerInterceptor {

    @Autowired(required = false)
    private RequestContext requestContext;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            // 从请求头获取链路ID，如果没有则生成新的
            String traceId = request.getHeader(TraceContext.TRACE_ID_HEADER);
            if (traceId == null || traceId.trim().isEmpty()) {
                traceId = TraceContext.generateTraceId();
            }

            // 获取用户信息
            Long userId = null;
            String userName = null;
            try {
                if (requestContext != null) {
                    UserInfo user = requestContext.getUser();
                    if (user != null) {
                        userId = user.getId();
                        userName = user.getUserName();
                    }
                }
            } catch (Exception e) {
                // 用户信息获取失败，可能是未登录状态，继续处理
                log.debug("获取用户信息失败: {}", e.getMessage());
            }

            // 获取请求信息
            String requestUri = request.getRequestURI();
            String clientIp = getClientIpAddress(request);

            // 初始化链路追踪上下文
            TraceContext.initTrace(traceId, userId, userName, requestUri, clientIp);

            // 将链路ID添加到响应头
            response.setHeader(TraceContext.TRACE_ID_HEADER, traceId);

            return true;
        } catch (Exception e) {
            log.error("链路追踪拦截器处理失败: {}", e.getMessage(), e);
            // 即使失败也要继续处理请求
            return true;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        try {
            // 记录请求完成信息
            TraceContext.TraceInfo traceInfo = TraceContext.getCurrentTraceInfo();
            if (traceInfo != null) {
                log.info("请求完成 - TraceId: {}, URI: {}, 耗时: {}ms, 状态: {}", 
                        traceInfo.getTraceId(), 
                        traceInfo.getRequestUri(), 
                        traceInfo.getElapsedTime(),
                        response.getStatus());
            }

            // 清理链路追踪上下文
            TraceContext.clear();
        } catch (Exception e) {
            log.error("链路追踪拦截器清理失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xip = request.getHeader("X-Real-IP");
        String xfor = request.getHeader("X-Forwarded-For");
        
        if (xfor != null && !xfor.isEmpty() && !"unknown".equalsIgnoreCase(xfor)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = xfor.indexOf(",");
            if (index != -1) {
                return xfor.substring(0, index);
            } else {
                return xfor;
            }
        }
        
        xfor = xip;
        if (xfor != null && !xfor.isEmpty() && !"unknown".equalsIgnoreCase(xfor)) {
            return xfor;
        }
        
        if (xfor == null || xfor.isEmpty() || "unknown".equalsIgnoreCase(xfor)) {
            xfor = request.getHeader("Proxy-Client-IP");
        }
        
        if (xfor == null || xfor.isEmpty() || "unknown".equalsIgnoreCase(xfor)) {
            xfor = request.getHeader("WL-Proxy-Client-IP");
        }
        
        if (xfor == null || xfor.isEmpty() || "unknown".equalsIgnoreCase(xfor)) {
            xfor = request.getHeader("HTTP_CLIENT_IP");
        }
        
        if (xfor == null || xfor.isEmpty() || "unknown".equalsIgnoreCase(xfor)) {
            xfor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        
        if (xfor == null || xfor.isEmpty() || "unknown".equalsIgnoreCase(xfor)) {
            xfor = request.getRemoteAddr();
        }
        
        return xfor;
    }
}
